package com.jugheadzhou.auth.core.auth;

import com.alibaba.fastjson.JSON;
import com.jugheadzhou.auth.core.common.exception.UnauthorizedException;
import com.jugheadzhou.auth.core.webapi.utils.ApplicationContextUtils;
import com.jugheadzhou.auth.util.JWTUtils;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.ExpiredJwtException;
import io.jsonwebtoken.MalformedJwtException;
import io.jsonwebtoken.SignatureException;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.core.env.Environment;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
import java.util.HashMap;
import java.util.Map;

@Slf4j
public class SystemContext {
    private static String tokenHead = "Bearer ";
    private static String tokenHeader = "Authorization";
    private static final String CLAIM_KEY_USERNAME = "sub";
    private static final String CLAIM_KEY_USER = "user";
    private static final String CLAIM_KEY_USERID = "uerid";
    private static final String CLAIM_KEY_NAME = "name";
    private static final String CLAIM_KEY_DEPTNAME = "detptname";

    private SystemContext() {
    }

    /**
     * 待废弃，token最终放在gateway管理
     *
     * @return
     * @deprecated
     */
    @Deprecated
    public static String getToken() {
        String authHeader = getRequest().getHeader(tokenHeader);
        String authToken;
        if (authHeader != null && authHeader.startsWith(tokenHead)) {
            authToken = authHeader.substring(tokenHead.length());
        } else {
            log.error("请求头不合法");
            throw new UnauthorizedException("请求头不合法");
        }
        return authToken;
    }

    private static HttpServletRequest getRequest() {
        return ((ServletRequestAttributes) RequestContextHolder
                .getRequestAttributes()).getRequest();
    }


    /**
     * @return
     * @Author muweijun
     * @Description 获取登录人
     * @Date 17:40     2021/5/6
     * @Param
     **/
    public static <T> T getUser(Class<T> resultClass) {
        // TODO 兼容旧的获取用户信息方式 待稳定运行后可删除旧的方式
        Environment environment = ApplicationContextUtils.getBean(Environment.class);
        String userSource = environment.getProperty("userSource");
        if (StringUtils.isNotBlank(userSource) && "3".equals(userSource)) {
            return getUserByHeader(resultClass);
        }
        // TODO 待删除的旧的获取当前登录用户的方式
        Map<String, Object> userFromToken = getUserFromToken(getToken());
        String o = JSON.toJSONString(userFromToken);
        if (!StringUtils.isEmpty(o)) {
            return JSON.parseObject(o, resultClass);
        }
        return null;
    }

    /**
     * 获取当前登录人信息
     *
     * @param resClass
     * @param <T>
     * @return 返回指定登录用户信息对象
     */
    public static <T> T getUserByHeader(Class<T> resClass) {
        HttpServletRequest request = getRequest();
        Map<String, String> userMap = new HashMap<>();
        userMap.put("id", getHeader(request, CLAIM_KEY_USERID));
        userMap.put("deptId", getHeader(request, CLAIM_KEY_USER));
        userMap.put("nicknames", getHeader(request, CLAIM_KEY_NAME));
        userMap.put("deptName", getHeader(request, CLAIM_KEY_DEPTNAME));
        userMap.put("doctorName", getHeader(request, CLAIM_KEY_NAME));
        userMap.put("loginName", getHeader(request, CLAIM_KEY_USERNAME));
        String userStr = JSON.toJSONString(userMap);
        if (StringUtils.isNotBlank(userStr)) {
            return JSON.parseObject(userStr, resClass);
        }
        return null;
    }

    /**
     * 获取当前登录人信息
     *
     * @return 返回自定义登录用户信息对象
     */
    public static LoginUser getUser() {
        HttpServletRequest request = getRequest();
        LoginUser user = new LoginUser();
        // TODO 兼容旧的获取用户信息方式 待稳定运行后可删除旧的方式
        Environment environment = ApplicationContextUtils.getBean(Environment.class);
        String userSource = environment.getProperty("userSource");
        if (StringUtils.isNotBlank(userSource) && "3".equals(userSource)) {
            String curUserId = getHeader(request, CLAIM_KEY_USERID);
            if (StringUtils.isBlank(curUserId)) {
                throw new UnauthorizedException("登录信息缺失");
            }
            user.setId(Integer.valueOf(curUserId));
            user.setNickname(getHeader(request, CLAIM_KEY_NAME));
            user.setUsername(getHeader(request, CLAIM_KEY_USERNAME));
            user.setDeptId(Integer.valueOf(getHeader(request, CLAIM_KEY_USER)));
            user.setDeptName(getHeader(request, CLAIM_KEY_DEPTNAME));
            return user;
        } else {
            // TODO 待删除的旧的获取当前登录用户的方式
            Map<String, Object> userFromToken = getUserFromToken(getToken());
            return JSON.parseObject(JSON.toJSONString(userFromToken), LoginUser.class);
        }
    }

    /**
     * 解码请求头
     *
     * @param request
     * @param key
     * @return
     */
    private static String getHeader(HttpServletRequest request, String key) {
        try {
            String header = request.getHeader(key);
            if (StringUtils.isNotBlank(header)) {
                return URLDecoder.decode(request.getHeader(key), "UTF-8");
            }
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }
        return null;
    }

    public static Map<String, Object> getUserFromToken(String token) {
        Map<String, Object> map = new HashMap<>();
        try {
            Claims claims = JWTUtils.parseTokenAndGetBody(token);
            map.put("id", claims.get(CLAIM_KEY_USERID, Integer.class).toString());
            map.put("deptId", claims.get(CLAIM_KEY_USER, Integer.class));
            map.put("nickname", claims.get(CLAIM_KEY_NAME, String.class));
            map.put("deptName", claims.get(CLAIM_KEY_DEPTNAME, String.class));
            map.put("username", claims.get(CLAIM_KEY_USERNAME, String.class));
        } catch (ExpiredJwtException e1) {
            log.error("token is expired", e1);
            throw new UnauthorizedException("授权访问token已过期");
        } catch (MalformedJwtException e2) {
            log.error("can't parse token", e2);
            throw new UnauthorizedException("授权访问token内容错误");
        } catch (SignatureException e3) {
            log.error("token signature is wrong", e3);
            throw new UnauthorizedException("授权访问token签名无效");
        } catch (Exception e) {
            log.error("there had prolem to parse token: {}", token, e);
            throw new UnauthorizedException("未知错误无法验证授权访问token");
        }
        return map;
    }

}
